package com.ttbj.product.api.impl;

import java.io.InputStream;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import com.ttbj.cargo.dao.CargoMapper;
import com.ttbj.cargo.po.Cargo;
import com.ttbj.constant.order.DelayTimeEnum;
import com.ttbj.core.util.DtoTransitionUtils;
import com.ttbj.core.util.IDUtils;
import com.ttbj.core.util.QRUtil;
import com.ttbj.core.util.RegexUtil;
import com.ttbj.core.util.security.aes.AESUtils;
import com.ttbj.exception.WebException;
import com.ttbj.freight.component.OrderStateComponent;
import com.ttbj.ftp.client.FTPClientHelper;
import com.ttbj.ftp.constant.FtpConstant;
import com.ttbj.order.dao.OrderMapper;
import com.ttbj.order.po.Order;
import com.ttbj.pay.dao.PayMapper;
import com.ttbj.pay.po.Pay;
import com.ttbj.product.api.AppletUserFacade;
import com.ttbj.product.api.OrderFacade;
import com.ttbj.product.api.OwnerFacade;
import com.ttbj.product.api.WaybillFacade;
import com.ttbj.product.bean.dto.CargoDto;
import com.ttbj.product.bean.dto.DriverDto;
import com.ttbj.product.bean.dto.OrderDto;
import com.ttbj.product.bean.dto.OwnerDto;
import com.ttbj.product.bean.dto.QRCodeOrderDto;
import com.ttbj.product.bean.dto.UserDto;
import com.ttbj.qr.dao.QRMapper;
import com.ttbj.qr.po.QR;
import com.ttbj.refund.dao.RefundOrderMapper;
import com.ttbj.refund.po.RefundOrder;
import com.ttbj.timer.po.AchievedOrder;
import com.ttbj.timer.service.achieved.AchievedService;
import com.ttbj.util.Assert;
import com.ttbj.util.ResultUtil;
import com.ttbj.util.ViewModelUtil;
import com.ttbj.utils.QRCodeUtil;
import com.zywl.common.utils.DateUtils;

@Service("orderFacade")
public class OrderFacadeImpl implements OrderFacade {
	private static final Logger logger = LoggerFactory.getLogger(OrderFacadeImpl.class);

	@Autowired
	private OwnerFacade ownerFacade = null;

	@Autowired
	private ThreadPoolTaskExecutor executor = null;

	@Autowired
	private OrderMapper orderMapper = null;

	@Autowired
	private CargoMapper cargoMapper = null;

	@Autowired
	private OrderStateComponent orderStateComponent = null;

	@Autowired
	private FTPClientHelper fTPClientHelper = null;

	@Autowired
	private QRMapper qrMapper = null;

	@Autowired
	private WaybillFacade waybillFacade = null;

	@Autowired
	private AppletUserFacade appletUserFacade = null;

	@Autowired
	private PayMapper payMapper = null;
	
	@Autowired
	private RefundOrderMapper refundOrderMapper = null;
	
	@Autowired
	private AchievedService achievedService =null;

	@Override
	public void createMoveOrder(OwnerDto sender, OwnerDto reciver, String openId, OrderDto orderDto) throws Exception {
		try {
			Future<Long> sSubmit = executor.submit(() -> ownerFacade.addOwner(openId, sender.isSender(0)));
			Future<Long> rSubmit = executor.submit(() -> ownerFacade.addOwner(openId, reciver.isSender(1)));
			Long senderId = sSubmit.get();
			Long reciverId = rSubmit.get();
			if (null == reciverId || null == senderId) {
				ResultUtil.throwExcepion(ViewModelUtil.buildFailure(9999, "请重新填写地址资料"), "添加寄件人或是收件人时出错");
			}
			orderDto.senderId(senderId).reciverId(reciverId).payState(-1);
			logger.info("订单信息:{}", orderDto);
			 Order order = (Order) DtoTransitionUtils.trans(Order.class, orderDto);
			if (!Assert.assertThan0(orderMapper.insertSelective(order))) {
				ResultUtil.throwExcepion(ViewModelUtil.buildFailure(9999, "未知错误"), "添加订单信息时出错");
			}
		} catch (InterruptedException e) {
			throw e;
		} catch (ExecutionException e) {
			throw e;
		}

	}

	@Override
	public OrderDto createCarriageOrder(String openId, OrderDto orderDto, CargoDto cargoDto) {
		Cargo cargo = (Cargo) DtoTransitionUtils.trans(Cargo.class, cargoDto);
		cargoMapper.insertSelective(cargo);
		Long cargoId = cargo.getCargoId();
		if (null == cargoId) {
			logger.info("未生成cargoId");
			return null;
		}
		orderDto.cargo(cargoId);
		Order order = (Order) DtoTransitionUtils.trans(Order.class, orderDto);
		orderMapper.insertSelective(order);
		Long orderId = order.getOrderId();
		if (orderId == null) {
			logger.info("未生成订单id");
			return null;
		}
		orderDto.setOrderId(orderId);
		orderStateComponent.addOrderStateCache(orderId, orderDto.getOrderDriverRequire());
		return orderDto;
	}

	@Override
	public OrderDto queryOrder(Long orderId) {
		Order order = orderMapper.selectByPrimaryKey(orderId);
		return (OrderDto) DtoTransitionUtils.trans(OrderDto.class, order);
	}

	@Override
	public void updateOrder(OrderDto orderDto) throws Exception {
		Order order = (Order) DtoTransitionUtils.trans(Order.class, orderDto);
		int code = orderMapper.updateByPrimaryKeySelective(order);
		if (1 == Integer.compare(0, code)) {
			ResultUtil.throwExcepion(ResultUtil.createFail("messages", 407), "更新订单失败");
		}

	}

	private List<OrderDto> getOwner(String openId, List<OrderDto> orders, Integer isSender) {
		if (Assert.isEmpty(orders))
			return null;
		if (isSender.equals(0)) {
			orders.stream().filter(order -> order != null).filter(order -> null != order.getOrderSender()).forEach(order -> order.setSender(ownerFacade.getOwner(openId, order.getOrderSender(), isSender)));
		} else {
			orders.stream().filter(order -> order != null).filter(order -> null != order.getOrderReciver()).forEach(order -> order.setReciver(ownerFacade.getOwner(openId, order.getOrderReciver(), isSender)));

		}
		orders.stream().filter(order -> order != null).filter(order -> null != order.getOrderSender()).forEach(order -> order.setSender(ownerFacade.getOwner(openId, order.getOrderSender(), isSender)));
		return orders;
	}

	private List<OrderDto> getCargos(String openId, List<OrderDto> orders) {
		if (Assert.isEmpty(orders))
			return null;
		orders.stream().filter(order -> order != null).filter(order -> null != order.getOrderCargo()).forEach(order -> order.setCargoDto(getCargo(order)));
		return orders;
	}

	private CargoDto getCargo(OrderDto order) {
		try {
			if (!Assert.assertNonNullField0(order, "orderCargo"))
				return null;
			Cargo cargo = cargoMapper.selectByPrimaryKey(order.getOrderCargo());
			if (null != cargo) {
				return (CargoDto) DtoTransitionUtils.trans(CargoDto.class, cargo);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public List<OrderDto> simpleOrderAll(UserDto userDto) {
		Long userId = userDto.getId();
		if (null == userId) {
			return null;
		}
		return orderMapper.getOrderByOpenId(userId);
	}

	@Override
	public List<OrderDto> orderAll(UserDto userDto) {
		String openId = userDto.getOpenId();
		List<OrderDto> orders = simpleOrderAll(userDto);
		if (Assert.isEmpty(orders))
			return null;
		return getCargos(openId, getOwner(openId, getOwner(openId, orders, 1), 0));
	}

	@Override
	public OrderDto orderDetail(Long orderId, Integer flag) throws Exception {
		if (null == orderId || null == flag) {
			return null;
		}
		Order order = orderMapper.selectByPrimaryKey(orderId);
		if (null == order) {
			return null;
		}
		OrderDto orderDto = (OrderDto) DtoTransitionUtils.trans(OrderDto.class, order);
		Long orderSender = order.getOrderSender();
		Long orderReciver = order.getOrderReciver();
		OwnerDto sender = ownerFacade.getOwner(null, orderSender, 0);
		OwnerDto reciver = ownerFacade.getOwner(null, orderReciver, 1);
		orderDto.setSender(sender);
		orderDto.setReciver(reciver);
		UserDto user = appletUserFacade.getUser(new UserDto(order.getOrderWxUser()));
		if (null != user) {
			orderDto.setOpenId(user.getOpenId());
		}
		if (0 == flag) {
			Long orderCargo = order.getOrderCargo();
			if (orderCargo != null) {
				Cargo cargo = cargoMapper.selectByPrimaryKey(orderCargo);
				if (null != cargo) {
					CargoDto cargoDto = (CargoDto) DtoTransitionUtils.trans(CargoDto.class, cargo);
					orderDto.setCargoDto(cargoDto);
				}
			}
			List<DriverDto> drivers = waybillFacade.allDriver(orderDto.getOrderId());
			orderDto.setDrivers(drivers);
		}
		logger.info("订单信息{}", orderDto);
		return orderDto;
	}

	/**
	 * 1.生成二维码内容 2.放入数据库
	 * 
	 * @throws Exception
	 */
	@Override
	public String newOrderCode(OrderDto orderDto) throws Exception {
		if (!Assert.assertNonNullField0(orderDto, "orderId"))
			return null;
		Long orderId = orderDto.getOrderId();
		long currentTimeMillis = System.currentTimeMillis();// 时间戳
		String orderIdEncrypted = AESUtils.encrypt(String.valueOf(orderId));// 订单号的AES
		String content = new StringBuffer("/").append(currentTimeMillis).append("/").append(orderIdEncrypted).toString();
		InputStream streamQr = QRUtil.streamQr(content, "jpg");// 图片流
		String url = imageUrl(currentTimeMillis); // 请求后缀url
		fTPClientHelper.changeOrMakeDirectory(FtpConstant.BASE_URL + directory(currentTimeMillis));// 创建或是进入FTP目录
		fTPClientHelper.storeFile(FtpConstant.BASE_URL + url, streamQr); // ftp保存图片
		QR qr = new QR(orderId, com.ttbj.util.DateUtils.getCurDttStr(), url, content);
		qrMapper.insertSelective(qr);
		logger.info("生成的订单二维码:{}", url);
		return url;
	}

	/*
	 * 1.获取订单信息 2.封装二维码地址信息 3.检查是否超时
	 */
	@Override
	public QRCodeOrderDto getOrderCode(Long orderId) throws Exception {
		QR QR = qrMapper.selectByOrderId(orderId);
		Assert.assertNonNullField(QR, "二维码图片不存在", 402, null, "qrUrl", "qrContent");
		if (QRCodeUtil.isOverTime(QR.getQrContent())) {
			ResultUtil.throwExcepion(ResultUtil.createFail("messages", 404), "二维码图片已超时");
		}
		QRCodeOrderDto dto = getQROrderInfo(orderId);
		dto.setQRCodeurl(QR.getQrUrl());
		return dto;
	}

	/*
	 * 获取订单信息 检查是否超时 检查内容是否篡改
	 */
	@Override
	public QRCodeOrderDto getOrderCodeInfo(String qr) throws Exception {
		Long id = QRCodeUtil.getId(qr);
		QR QR = qrMapper.selectByOrderId(id);// 数据库的二维码信息
		Assert.assertNonNullField(QR, "二维码图片不存在", 402, null, "qrUrl", "qrContent");
		if (QRCodeUtil.isTamper(QR.getQrContent(), qr)) { // 验证是否二维码信息是否一致
			ResultUtil.throwExcepion(ResultUtil.createFail("messages", 406), "二维码信息已被篡改");
		}
		return getQROrderInfo(id);
	}

	/**
	 * 在ftp服务器中的目录
	 * 
	 * @param curMill
	 * @return
	 */
	private String directory(Long curMill) {
		String date = DateUtils.getDate2SStr2(new Date());
		StringBuffer sb = new StringBuffer(FtpConstant.ORDER_URL).append(date).append("/");
		return sb.toString();
	}

	/**
	 * 图片url 目录图片名称组成的图片url
	 * 
	 * @param curMill
	 * @return
	 */
	private String imageUrl(Long curMill) {
		StringBuffer sb = new StringBuffer(directory(curMill));
		return sb.append(IDUtils.genImageName()).append(".jpg").toString();
	}

	private QRCodeOrderDto getQROrderInfo(Long orderId) throws Exception {
		OrderDto order = simpleDetailOrder(orderId);
		Assert.assertNonNullField(order, "订单信息不存在", 405, null, "reciver", "sender");
		OwnerDto sender = order.getSender();
		OwnerDto reciver = order.getReciver();
		String senderPhone = sender.getOwnerPhone();
		Assert.assertNonNullObj(senderPhone, 303, "联系方式不存在");
		String mobileNoRegexReplaceAsterisk = RegexUtil.mobileNoRegexReplaceAsterisk(senderPhone);
		QRCodeOrderDto dto = new QRCodeOrderDto(null, sender.getOwnerName(), mobileNoRegexReplaceAsterisk, reciver.getOwnerAddr(), sender.getOwnerAddr());
		return dto;
	}

	@Override
	public void isPay(String orderId) throws Exception {
		Assert.assertNonNullObj(orderId, 234);// orderId不存在非空判断
		Assert.assertNumeric(orderId,408); // 数字判断
		Integer payState = orderMapper.getPayState(Long.valueOf(orderId));
		Assert.assertNonNullObj(payState, 234); // 非空判断
		if (payState.equals(0)) {// 支付判断
			ResultUtil.throwExcepion(ResultUtil.createFail("messages", 233));
		}
	}

	@Override
	public void orderRefund(Long orderId) throws Exception {
		Pay pay = payMapper.selectByOrderId(orderId);
		Assert.assertNonNullField(pay, 405, "payNum", "orderNum","allPay");
		int code = refundOrderMapper.insertSelective(new RefundOrder(orderId, pay.getPayNum(), String.valueOf(pay.getAllPay()), DateUtils.getDate2MStr(new Date()),pay.getOrderNum()));
		if(code <= 0 ){
			ResultUtil.throwExcepion(ResultUtil.createFail("messages", 407));
		}
	}

}
